﻿using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Speech;
using System.Speech.Synthesis;
using System.Speech.AudioFormat;
using System.Runtime.InteropServices;
using Yeti.MMedia.Mp3;
using WaveLib;

namespace TTS
{
    
    public class TextToSpeech
    {
        public static String OGG = "ogg";
        public static String MP3 = "mp3";
        public static String WAV = "wav";
 
        private SpeechSynthesizer synth = new SpeechSynthesizer();
        private static List<string> lstVoice = getTTSEngineInfo();

        private int voiceIndex;

        public TextToSpeech(int voiceIndex) 
        {
            if (voiceIndex >= lstVoice.Capacity-1)
                voiceIndex = 0;
            this.voiceIndex = voiceIndex;
            init();
        }

        public static List<string> getListVoice()
        {
            return lstVoice;
        }
        
        private static List<string> getTTSEngineInfo(){
            SpeechSynthesizer synth = new SpeechSynthesizer();
            List<string> lstVoice = new List<string>();

            // Output information about all of the installed voices. 
            Console.WriteLine("Installed voices -");
            foreach (InstalledVoice voice in synth.GetInstalledVoices())
            {
                lstVoice.Add(voice.VoiceInfo.Name);
                VoiceInfo info = voice.VoiceInfo;
                string AudioFormats = "";
                foreach (SpeechAudioFormatInfo fmt in info.SupportedAudioFormats)
                {
                    AudioFormats += String.Format("{0}\n",
                    fmt.EncodingFormat.ToString());
                }

                Console.WriteLine(" Name:          " + info.Name);
                Console.WriteLine(" Culture:       " + info.Culture);
                Console.WriteLine(" Age:           " + info.Age);
                Console.WriteLine(" Gender:        " + info.Gender);
                Console.WriteLine(" Description:   " + info.Description);
                Console.WriteLine(" ID:            " + info.Id);
                Console.WriteLine(" Enabled:       " + voice.Enabled);
                if (info.SupportedAudioFormats.Count != 0)
                {
                    Console.WriteLine(" Audio formats: " + AudioFormats);
                }
                else
                {
                    Console.WriteLine(" No supported audio formats found");
                }

                string AdditionalInfo = "";
                foreach (string key in info.AdditionalInfo.Keys)
                {
                    AdditionalInfo += String.Format("  {0}: {1}\n", key, info.AdditionalInfo[key]);
                }

                Console.WriteLine(" Additional Info - " + AdditionalInfo);
                Console.WriteLine();
            }
            return lstVoice;
        }

        public void init()
        {
            synth.SelectVoice((string)lstVoice[this.voiceIndex]);
        }
        
        public byte[] getAudioBytes(String text, String extension)
        {
            lock (this)
            {
                if (text == null || text.Equals(""))
                    return new byte[0];

                MemoryStream streamWav = new MemoryStream();
                synth.SetOutputToWaveStream(streamWav);

                // Speak a string.
                synth.Speak(text);
                byte[] buffer = streamWav.GetBuffer();
                if (extension.Equals(WAV)) //Wav
                {
                    return buffer;
                }
                else //Mp3
                {
                    WaveStream InStr = new WaveStream(new MemoryStream(buffer));
                    MemoryStream streamMp3 = new MemoryStream();
                    Mp3Writer writer = new Mp3Writer(streamMp3, InStr.Format);

                    byte[] buff = new byte[writer.OptimalBufferSize];
                    int read = 0;
                    while ((read = InStr.Read(buff, 0, buff.Length)) > 0)
                    {
                        writer.Write(buff, 0, read);
                    }

                    return streamMp3.GetBuffer();
                }
            }
        }

        private void finish()
        {
            // Set the synthesizer output to null to release the stream. 
            synth.SetOutputToNull();
        }
        static void Main(string[] args)
        {

            TextToSpeech p = new TextToSpeech(1);
            FileStream fs = File.OpenWrite("C:\\Users\\DatTT\\Desktop\\ttt.mp3");
            byte[] b = p.getAudioBytes("Hôm nay tôi đi học rất vui đó", TextToSpeech.MP3);
            Console.WriteLine(b.Length);
            fs.Write(b, 0, b.Length);
            fs.Close();

            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }
    }
}
